﻿
module Sustainalytics.SearchBox {

    import Common = Sustainalytics.Common;

    export class SearchBoxController {
        // min delay between input change searches
        public inputChangeSearchFrequency: number = 500;

        // whether current search box results are visible
        public isVisible: boolean = false;

        // last page index
        public lastSkip: number = -1;

        // last page size
        public take: number = 20;

        // last items count
        public lastItemsCount: number = 0;

        // current scroll top
        public scrollTop: number = 0;

        // last scroll top
        public lastScrollTop: number = 0;

        // search service name
        public searchServiceName: string;

        // service used for searching
        public searchService: ISearchBoxService = null;

        // whether searching is still running
        public searching: boolean = false;

        // search data used for searching
        public searchData: any = null;

        // items available in search list
        public items: any[] = new Array();


        // query timeout used to throttle the request
        private queryTimeout: any = null;

        public searchOnEmptyData: boolean;


        // Ctor.
        constructor(private $scope: ng.IScope, private $sce: ng.ISCEService, private $q: ng.IQService) {

            this.searchOnEmptyData = false;

            // set current controller inside current scope
            this.$scope['search'] = this;

            this.items = new Array();

            // set search data if found
            //$scope.$on('searchBox.countryHasValue', function (event, data) {
            //    this.searchData = data;
            //});
        }

        // search 1st page
        public search(withInputTimeout: boolean): ng.IPromise<{}> {
            var ctrl = this;

            // remove previous timeout
            if (ctrl.queryTimeout) {
                window.clearTimeout(ctrl.queryTimeout);
            }

            var skip: number = 0;

            if (withInputTimeout) {
                ctrl.queryWithInputTimeout(skip, false);

                var def = ctrl.$q.defer();
                def.resolve();
                return def.promise;
            }
            else {
                var promise = ctrl.query(skip, false);
                return promise;
            }
        }

        // get next page
        public searchNextPage(withInputTimeout: boolean) {
            var ctrl = this;

            // if previous search had 0 results then cancel current query
            if (ctrl.lastItemsCount == 0) {
                return;
            }

            var skip: number = ctrl.lastSkip + ctrl.take;

            if (withInputTimeout) {
                ctrl.queryWithInputTimeout(skip, true);
            }
            else {
                ctrl.query(skip, true);
            }
        }

        // mark matched portions of a string
        public getMarkedString(str: string, term: string) {

            // regex escape term
            var termEsc = term.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");

            // create regex to search the string for the provided term
            var regex = new RegExp(termEsc, "ig");

            var curIndex = 0;

            while (true) {
                var match = regex.exec(str.substr(curIndex, str.length - curIndex));

                if (!match || match.length === 0) {
                    break;
                }

                var matchStr: string = match[0];
                var transStr = "<u>" + matchStr + "</u>";

                var before = str.substr(0, curIndex + match.index);
                var after = str.substr(curIndex + match.index + matchStr.length, str.length - (curIndex + match.index + matchStr.length));

                str = before + transStr + after;
                curIndex = curIndex + match.index + transStr.length;
            }

            return this.$sce.trustAsHtml(str);
        }

        // reset current search box
        private reset() {
            this.items = new Array();
            this.lastSkip = -1;
            this.lastItemsCount = 0;            
        }

        // query 
        private query(skip: number, append: boolean): ng.IPromise<{}> {

            var ctrl = this;

            if (!ctrl.searchOnEmptyData && (ctrl.searchData === '' || ctrl.searchData == null || typeof(ctrl.searchData) == 'undefined')) {
                ctrl.reset();                
                return;
            }

            // set searching as running
            ctrl.searching = true;

            // query the search service to obtain next page
            var lstPromise: ng.IHttpPromise<any[]> = ctrl.searchService.Search(ctrl.searchData, skip, ctrl.take);

            lstPromise
            // search done
                .success(function (lstRes: any[]) {
                    // update members based on current result state
                    ctrl.lastSkip = skip;

                    if (!append) {
                        ctrl.items = new Array();
                    }

                    if (lstRes) {
                        ctrl.lastItemsCount = lstRes.length;

                        $(lstRes).each(function () {
                            ctrl.items.push(this);
                        });
                    }
                    else {
                        ctrl.lastItemsCount = 0;
                    }                    
                })
            // error searching
                .error(function (err: any) {
                })
            // always executing after resolved or rejected
            ['finally'](function () {
                    ctrl.searching = false;
            });

            return lstPromise;
        }

        // query using timeout
        private queryWithInputTimeout(pageIndex: number, append: boolean) {

            var ctrl = this;

            // remove previous timeout
            if (ctrl.queryTimeout) {
                window.clearTimeout(ctrl.queryTimeout);
                ctrl.queryTimeout = null;
            }

            // add new timeout
            ctrl.queryTimeout = window.setTimeout(function () {
                ctrl.$scope.$evalAsync(function () {
                    ctrl.queryTimeout = null;
                    // start query
                    ctrl.query(pageIndex, append);
                });
            }, ctrl.inputChangeSearchFrequency);
        }

        public searchBoxFocus() {
            $(".portfolio-search-results").removeClass("ng-hide");
        }
    }


    // create/get search module
    var companySearchModule = angular.module('Sustainalytics.SearchBox');

    // add search box controller
    companySearchModule.controller('SearchBoxController',
        ['$scope', '$sce', '$q', SearchBoxController]);
}